`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          U_DLY                   = 0;
localparam          CLK_PRD                 = 5;
localparam          DWID                    = 3;
localparam          MAX_PNUM                = 32;    //must be >=2
localparam          MUX_NUM                 = MAX_PNUM-2+1;
localparam          MAX_BIN_BW              = log2_f(MAX_PNUM);
localparam          MAX_OH_BW               = MAX_PNUM;
localparam          LEFT_NUM                = (DWID*MAX_PNUM-1)%32+1;
localparam          DAT_NUM                 = 20000;

reg                                         rst_n;
reg                                         clk;

reg                 [MAX_BIN_BW-1:0]        sel_bin;
reg                 [DWID*MAX_PNUM-1:0]     np_dat;
wire                [MAX_OH_BW-1:0]         sel_oh[MUX_NUM-1:0];
wire                [DWID-1:0]              op_dat_oh[MUX_NUM-1:0];
wire                [DWID-1:0]              op_dat_bin[MUX_NUM-1:0];
reg                 [MUX_NUM-1:0]           err_flag;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_n2o", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin:GEN_SEL_DAT
    integer         i;
    integer         cnt_dat;

    sel_bin = 0;
    np_dat = 0;
    cnt_dat = 0;

    @(posedge rst_n);

    while (cnt_dat<DAT_NUM) begin
        @(posedge clk);
        #U_DLY;

        i = 0;
        sel_bin = $urandom();
        while((32*i+32)<DWID*MAX_PNUM) begin
            np_dat[32*i+:32] = $urandom();
            i = i+1;
        end
        np_dat[32*i+:LEFT_NUM] = $urandom();
        cnt_dat = cnt_dat + 1;
    end
    rgrs.one_chk_done("data num is done.");
end

genvar g0;
generate for (g0=0; g0<MUX_NUM; g0=g0+1) begin:G_PNUM

    bin2onehot #(
        .OH_BW                          (g0+2                           ) 	// bit width of one-hot number
    ) u_bin2oh( 
        .bin                            (sel_bin[0+:log2_f(g0+2)]       ),	// binary number
        .oh                             (sel_oh[g0][0+:(g0+2)]          )	// one-hot number
    );

    n2o #(
        .PNUM                           (g0+2                           ),	// source port number
        .DWID                           (DWID                           ),	// data width of one port
        .SMODE                          ("ONEHOT"                       ) 	// sel is onehot signal
    ) u_n2o_oh ( 
        .sel                            (sel_oh[g0][0+:(g0+2)]          ),	// support one-hot and all-zero input when SMODE
        .np_dat                         (np_dat[0+:DWID*(g0+2)]         ),
        .op_dat                         (op_dat_oh[g0]                  )
    );

    n2o #(
        .PNUM                           (g0+2                           ),	// source port number
        .DWID                           (DWID                           ),	// data width of one port
        .SMODE                          ("BINARY"                       ) 	// sel is binary signal
    ) u_n2o_bin ( 
        .sel                            (sel_bin[0+:log2_f(g0+2)]       ),	// support one-hot and all-zero input when SMODE
        .np_dat                         (np_dat[0+:DWID*(g0+2)]         ),
        .op_dat                         (op_dat_bin[g0]                 )
    );
    
    always@(posedge clk or negedge rst_n) begin
        if (rst_n==1'b0) begin
            err_flag[g0] <= 1'b0;
        end else begin
            if ((op_dat_oh[g0]===op_dat_bin[g0]) || ((op_dat_bin[g0]==={DWID{1'bx}}) && (op_dat_oh[g0]==={DWID{1'b0}}))) begin
                ;
            end else begin
                err_flag[g0] <= 1'b1;
                $display("Error:%m op_dat_oh doesn't equal to op_dat_bin");
                $stop;
            end
        end
    end

end endgenerate

function integer log2_f;
    input   integer     n;

    integer             t;
    begin
        t = 1;

        while ((1<<t)<n) begin
            t = t +1;
        end

        if (n<=2)
            log2_f = 1;
        else if (n<=4)
            log2_f = 2;
        else if (n<=8)
            log2_f = 3;
        else if (n<=16)
            log2_f = 4;
        else if (n<=32)
            log2_f = 5;
        else if (n<=64)
            log2_f = 6;
        else if (n<=128)
            log2_f = 7;
        else if (n<=256)
            log2_f = 8;
        else if (n<=512)
            log2_f = 9;
        else if (n<=1024)
            log2_f = 10;
        else if (n<=2048)
            log2_f = 11;
        else if (n<=4096)
            log2_f = 12;
        else
            log2_f = t;
    end
endfunction

endmodule

